package main

import (
	"fmt"
	"github.com/smartwalle/alipay/v3"
	"github.com/smartwalle/xid"
	"log"
	"net/http"
)

var client *alipay.Client

const (
	kAppId      = "9021000131622561"
	kPrivateKey = "MIIEpQIBAAKCAQEAtq586bL2f17qMhXr8VEeZKAUIFi6tBvj7HopmWKQh9z6d9FoadF1gDvx5l/aFBWTwpJ8b5NIeC3EP4I4xdLgckW0szl3StK8ypvSwoOVUXWWT2z8uscKXDoEblJZVp2yNip95Z+D3TFAljU0ZS1ruQf9INGTbpAqgEowGUdzy4vFJRstUTk4ZJicdCh5PGq1lKmBfyeDJ0q3ODN2jXBt0wuDmaopcGqGvomK5fm6wF3su6UcYTmvOlogRH8Xk1cGhBIcC11QMBRW01z5RY4IbgYbNmMZaMlz2mV7pQwbzQ83S4rrHg8/MeaKV7cusgJuaPKiinLiZz4nuAc3xxU5GQIDAQABAoIBAQCi7rWSan/X0nvm+A5cSRFmhi/tObYr9cQvojWADJ0D0F/Ehg0udBbsrIpwAoWq7CPBoo1Bpoc4SPmD+01Pg2mUAf/M6jAvmA2yV5B+1IVVBh9t77Lpk6T15PkWvHPaAQR1syheqQsfOVJ1pjZ5Fy3A9hMaNlHchtChY4nKwiPRIfJws9fnmwMo60zJJ90PHXdVKa9qtSepTT6fbI7N+HCc0vDrTmFda1NG3SIz+0R/HwM/24NEmWv3Th+xC0UIN6gXcDDlcnbGXYp8FnPkDOmi6tb3x5mPFSbXkKA5akobfPewxjS+bHs+Hjf8d8S3DCu9jOC3+YuhX2ODGUGapJVBAoGBAN2GNor1ej9P9gfvntAN+1cm1gkmZFcKao1/cpjSt5FSe22Q+h7cEkruUEzn1gKWJOIFUB0FaJo8E8sjMI6DtsyaGr5OXUfQs1Gh8MbPMi55b8ZjLRD5w4gS5o6dB5N0LmcW5POvl3g53p/ZjGVtqfmG3LD5yqnnIl+0XGy3N6lFAoGBANMcvLBkqu/iNKSmgOjLy0LO3/nTSQoZLNwlbNZBX64bdvTp8gx0cK/G+NJIf+96ddswaEoTQGAgp5m4IR4zFKLjvvRkN+qNXTKPKSu94kg38cC+9z2A4Vnl+wdnzHUfFpTlvGs1ocwSq55YU/MoxG3nN0oHzx0kGtlUUdSXsgvFAoGAUO1lI6LGRDbsBL4vYIabGZ2gd7tE0N+HSaYTsWzZjwd4+/AI0BlJvYIOZ+oSLuO3GbMjL1b4fdAQ0xdJ9+Z6c4ig2IE8Zq4BtILauWacSIoooWs93YPBQQbWn6cSS3YYNaURg0zUoyFRCUiql6tWe0gfe6/lr+g2kIwNb9IHTZkCgYEAqQ/TX6NObMqHA/A/Pa6ueTL4lLWKQWcF0Mq7zR0PRXvDGMEc0LKS54F9E9FxetNj/INYkTG3lQOxlF2rT+byOLwP2OFFEjXhE7Mn8lqfEtySYpvLnVpPnVGaZUTPrF+YEuejq2uIxceR3j24BPt5ytWmJkf4qcqXIcHvwkM1F00CgYEAkO5Xsz4qJOJSabLf1S8La6M22nXltylHsD4vYO76Sn9Q1T59RlP1lKn6234JlQdfKUsk4xHj8/9zMq0gHVwTTdoMHIOSUr1Y/rAcaaNeFq6al66rwGmk6HDkjjpTG/uVUB8vvbyYBl5ngmeOmhvi5iRafQp6gWnBbHPQcP97IxA="
	kServerPort = "9989"
	PublicKey   = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6rQqrVzFxzFnB+8uiiBVoEB3oWW0ij3QLC3Rd1jgNv0nje39dao/YOe/k9EnZDWxLcbD/OBoWxlDJtZWpisQsiai9eeOWdWsdMS/HJW8ZlgvCTjMNF6bkrkKAAPsdUKeFmJtAIufkK3wkS5CBJGv8dlBX4Mda4P8Rf28fBjK6FbvqOa3PxKvAL1r6byCRi73qvWhYoNS6tRuAKzuBce/+RUOS/+K64YAe0ABz4ITIldXKSB1jMj9Ktje4eKIBDTyyypQi74p/DrDbb1NU8rbQ+3nqDfozLHA41LRhz7DR7jxgw5o0H+nXPLMfsSdLeMh40E5MjtmN471PBy+bAwCyQIDAQAB"
	// TODO 设置回调地址域名
	kServerDomain = ""
)

func main() {
	var err error

	if client, err = alipay.New(kAppId, kPrivateKey, false); err != nil {
		log.Println("初始化支付宝失败", err)
		return
	}

	if err = client.LoadAliPayPublicKey(PublicKey); err != nil {
		log.Println("加载公钥发生错误", err)
		return
	}
	http.HandleFunc("/alipay/pay", pay)
	http.HandleFunc("/alipay/callback", callback)
	http.HandleFunc("/alipay/notify", notify)

	http.ListenAndServe(":"+kServerPort, nil)
}

func pay(writer http.ResponseWriter, request *http.Request) {
	var tradeNo = fmt.Sprintf("%d", xid.Next())

	var p = alipay.TradePagePay{}
	p.NotifyURL = kServerDomain + "/alipay/notify"
	p.ReturnURL = kServerDomain + "/alipay/callback"
	p.Subject = "支付测试:" + tradeNo
	p.OutTradeNo = tradeNo
	p.TotalAmount = "10.00"
	p.ProductCode = "FAST_INSTANT_TRADE_PAY"

	url, _ := client.TradePagePay(p)
	http.Redirect(writer, request, url.String(), http.StatusTemporaryRedirect)
}

func callback(writer http.ResponseWriter, request *http.Request) {
	request.ParseForm()

	if err := client.VerifySign(request.Form); err != nil {
		log.Println("回调验证签名发生错误", err)
		writer.WriteHeader(http.StatusBadRequest)
		writer.Write([]byte("回调验证签名发生错误"))
		return
	}

	log.Println("回调验证签名通过")

	// 示例一：使用已有接口进行查询
	var outTradeNo = request.Form.Get("out_trade_no")
	var p = alipay.TradeQuery{}
	p.OutTradeNo = outTradeNo

	rsp, err := client.TradeQuery(p)
	if err != nil {
		writer.WriteHeader(http.StatusBadRequest)
		writer.Write([]byte(fmt.Sprintf("验证订单 %s 信息发生错误: %s", outTradeNo, err.Error())))
		return
	}

	if rsp.IsFailure() {
		writer.WriteHeader(http.StatusBadRequest)
		writer.Write([]byte(fmt.Sprintf("验证订单 %s 信息发生错误: %s-%s", outTradeNo, rsp.Msg, rsp.SubMsg)))
		return
	}
	writer.WriteHeader(http.StatusOK)
	writer.Write([]byte(fmt.Sprintf("订单 %s 支付成功", outTradeNo)))
}

func notify(writer http.ResponseWriter, request *http.Request) {
	request.ParseForm()

	var notification, err = client.DecodeNotification(request.Form)
	if err != nil {
		log.Println("解析异步通知发生错误", err)
		return
	}

	log.Println("解析异步通知成功:", notification.NotifyId)

	// 示例一：使用自定义请求进行查询
	var p = alipay.NewPayload("alipay.trade.query")
	p.AddBizField("out_trade_no", notification.OutTradeNo)

	var rsp *alipay.TradeQueryRsp
	if err = client.Request(p, &rsp); err != nil {
		log.Printf("异步通知验证订单 %s 信息发生错误: %s \n", notification.OutTradeNo, err.Error())
		return
	}
	if rsp.IsFailure() {
		log.Printf("异步通知验证订单 %s 信息发生错误: %s-%s \n", notification.OutTradeNo, rsp.Msg, rsp.SubMsg)
		return
	}

	log.Printf("订单 %s 支付成功 \n", notification.OutTradeNo)

	client.ACKNotification(writer)
}
